1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.base;
18
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.base.Joiner.MapJoiner;
21 import com.google.common.collect.ImmutableMap;
22 import com.google.common.collect.ImmutableMultimap;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Maps;
26
27 import junit.framework.AssertionFailedError;
28 import junit.framework.TestCase;
29
30 import java.io.IOException;
31 import java.util.Arrays;
32 import java.util.Iterator;
33 import java.util.Map;
34 import java.util.Set;
35
36
37
38
39
40
41 @GwtCompatible(emulated = true)
42 public class JoinerTest extends TestCase {
43 private static final Joiner J = Joiner.on("-");
44
45
46 private static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList();
47 private static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1);
48 private static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2);
49 private static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3);
50 private static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null);
51 private static final Iterable<Integer> ITERABLE_NULL_NULL
52 = Arrays.asList((Integer) null, null);
53 private static final Iterable<Integer> ITERABLE_NULL_1 = Arrays.asList(null, 1);
54 private static final Iterable<Integer> ITERABLE_1_NULL = Arrays.asList(1, null);
55 private static final Iterable<Integer> ITERABLE_1_NULL_2 = Arrays.asList(1, null, 2);
56 private static final Iterable<Integer> ITERABLE_FOUR_NULLS
57 = Arrays.asList((Integer) null, null, null, null);
58
59 public void testNoSpecialNullBehavior() {
60 checkNoOutput(J, ITERABLE_);
61 checkResult(J, ITERABLE_1, "1");
62 checkResult(J, ITERABLE_12, "1-2");
63 checkResult(J, ITERABLE_123, "1-2-3");
64
65 try {
66 J.join(ITERABLE_NULL);
67 fail();
68 } catch (NullPointerException expected) {
69 }
70 try {
71 J.join(ITERABLE_1_NULL_2);
72 fail();
73 } catch (NullPointerException expected) {
74 }
75
76 try {
77 J.join(ITERABLE_NULL.iterator());
78 fail();
79 } catch (NullPointerException expected) {
80 }
81 try {
82 J.join(ITERABLE_1_NULL_2.iterator());
83 fail();
84 } catch (NullPointerException expected) {
85 }
86 }
87
88 public void testOnCharOverride() {
89 Joiner onChar = Joiner.on('-');
90 checkNoOutput(onChar, ITERABLE_);
91 checkResult(onChar, ITERABLE_1, "1");
92 checkResult(onChar, ITERABLE_12, "1-2");
93 checkResult(onChar, ITERABLE_123, "1-2-3");
94 }
95
96 public void testSkipNulls() {
97 Joiner skipNulls = J.skipNulls();
98 checkNoOutput(skipNulls, ITERABLE_);
99 checkNoOutput(skipNulls, ITERABLE_NULL);
100 checkNoOutput(skipNulls, ITERABLE_NULL_NULL);
101 checkNoOutput(skipNulls, ITERABLE_FOUR_NULLS);
102 checkResult(skipNulls, ITERABLE_1, "1");
103 checkResult(skipNulls, ITERABLE_12, "1-2");
104 checkResult(skipNulls, ITERABLE_123, "1-2-3");
105 checkResult(skipNulls, ITERABLE_NULL_1, "1");
106 checkResult(skipNulls, ITERABLE_1_NULL, "1");
107 checkResult(skipNulls, ITERABLE_1_NULL_2, "1-2");
108 }
109
110 public void testUseForNull() {
111 Joiner zeroForNull = J.useForNull("0");
112 checkNoOutput(zeroForNull, ITERABLE_);
113 checkResult(zeroForNull, ITERABLE_1, "1");
114 checkResult(zeroForNull, ITERABLE_12, "1-2");
115 checkResult(zeroForNull, ITERABLE_123, "1-2-3");
116 checkResult(zeroForNull, ITERABLE_NULL, "0");
117 checkResult(zeroForNull, ITERABLE_NULL_NULL, "0-0");
118 checkResult(zeroForNull, ITERABLE_NULL_1, "0-1");
119 checkResult(zeroForNull, ITERABLE_1_NULL, "1-0");
120 checkResult(zeroForNull, ITERABLE_1_NULL_2, "1-0-2");
121 checkResult(zeroForNull, ITERABLE_FOUR_NULLS, "0-0-0-0");
122 }
123
124 private static void checkNoOutput(Joiner joiner, Iterable<Integer> set) {
125 assertEquals("", joiner.join(set));
126 assertEquals("", joiner.join(set.iterator()));
127
128 Object[] array = Lists.newArrayList(set).toArray(new Integer[0]);
129 assertEquals("", joiner.join(array));
130
131 StringBuilder sb1FromIterable = new StringBuilder();
132 assertSame(sb1FromIterable, joiner.appendTo(sb1FromIterable, set));
133 assertEquals(0, sb1FromIterable.length());
134
135 StringBuilder sb1FromIterator = new StringBuilder();
136 assertSame(sb1FromIterator, joiner.appendTo(sb1FromIterator, set));
137 assertEquals(0, sb1FromIterator.length());
138
139 StringBuilder sb2 = new StringBuilder();
140 assertSame(sb2, joiner.appendTo(sb2, array));
141 assertEquals(0, sb2.length());
142
143 try {
144 joiner.appendTo(NASTY_APPENDABLE, set);
145 } catch (IOException e) {
146 throw new AssertionError(e);
147 }
148
149 try {
150 joiner.appendTo(NASTY_APPENDABLE, set.iterator());
151 } catch (IOException e) {
152 throw new AssertionError(e);
153 }
154
155 try {
156 joiner.appendTo(NASTY_APPENDABLE, array);
157 } catch (IOException e) {
158 throw new AssertionError(e);
159 }
160 }
161
162 private static final Appendable NASTY_APPENDABLE = new Appendable() {
163 @Override
164 public Appendable append(CharSequence csq) throws IOException {
165 throw new IOException();
166 }
167 @Override
168 public Appendable append(CharSequence csq, int start, int end) throws IOException {
169 throw new IOException();
170 }
171 @Override
172 public Appendable append(char c) throws IOException {
173 throw new IOException();
174 }
175 };
176
177 private static void checkResult(Joiner joiner, Iterable<Integer> parts, String expected) {
178 assertEquals(expected, joiner.join(parts));
179 assertEquals(expected, joiner.join(parts.iterator()));
180
181 StringBuilder sb1FromIterable = new StringBuilder().append('x');
182 joiner.appendTo(sb1FromIterable, parts);
183 assertEquals("x" + expected, sb1FromIterable.toString());
184
185 StringBuilder sb1FromIterator = new StringBuilder().append('x');
186 joiner.appendTo(sb1FromIterator, parts.iterator());
187 assertEquals("x" + expected, sb1FromIterator.toString());
188
189 Integer[] partsArray = Lists.newArrayList(parts).toArray(new Integer[0]);
190 assertEquals(expected, joiner.join(partsArray));
191
192 StringBuilder sb2 = new StringBuilder().append('x');
193 joiner.appendTo(sb2, partsArray);
194 assertEquals("x" + expected, sb2.toString());
195
196 int num = partsArray.length - 2;
197 if (num >= 0) {
198 Object[] rest = new Integer[num];
199 for (int i = 0; i < num; i++) {
200 rest[i] = partsArray[i + 2];
201 }
202
203 assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
204
205 StringBuilder sb3 = new StringBuilder().append('x');
206 joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
207 assertEquals("x" + expected, sb3.toString());
208 }
209 }
210
211 public void test_useForNull_skipNulls() {
212 Joiner j = Joiner.on("x").useForNull("y");
213 try {
214 j = j.skipNulls();
215 fail();
216 } catch (UnsupportedOperationException expected) {
217 }
218 }
219
220 public void test_skipNulls_useForNull() {
221 Joiner j = Joiner.on("x").skipNulls();
222 try {
223 j = j.useForNull("y");
224 fail();
225 } catch (UnsupportedOperationException expected) {
226 }
227 }
228
229 public void test_useForNull_twice() {
230 Joiner j = Joiner.on("x").useForNull("y");
231 try {
232 j = j.useForNull("y");
233 fail();
234 } catch (UnsupportedOperationException expected) {
235 }
236 }
237
238 public void testMap() {
239 MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
240 assertEquals("", j.join(ImmutableMap.of()));
241 assertEquals(":", j.join(ImmutableMap.of("", "")));
242
243 Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
244 mapWithNulls.put("a", null);
245 mapWithNulls.put(null, "b");
246
247 try {
248 j.join(mapWithNulls);
249 fail();
250 } catch (NullPointerException expected) {
251 }
252
253 assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
254
255 StringBuilder sb = new StringBuilder();
256 j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
257 assertEquals("1:2;3:4;5:6", sb.toString());
258 }
259
260 public void testEntries() {
261 MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
262 assertEquals("", j.join(ImmutableMultimap.of().entries()));
263 assertEquals("", j.join(ImmutableMultimap.of().entries().iterator()));
264 assertEquals(":", j.join(ImmutableMultimap.of("", "").entries()));
265 assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator()));
266 assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries()));
267 assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator()));
268
269 Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
270 mapWithNulls.put("a", null);
271 mapWithNulls.put(null, "b");
272 Set<Map.Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet();
273
274 try {
275 j.join(entriesWithNulls);
276 fail();
277 } catch (NullPointerException expected) {
278 }
279
280 try {
281 j.join(entriesWithNulls.iterator());
282 fail();
283 } catch (NullPointerException expected) {
284 }
285
286 assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls));
287 assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator()));
288
289 StringBuilder sb1 = new StringBuilder();
290 j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries());
291 assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString());
292
293 StringBuilder sb2 = new StringBuilder();
294 j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator());
295 assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString());
296 }
297
298 @SuppressWarnings("ReturnValueIgnored")
299 public void test_skipNulls_onMap() {
300 Joiner j = Joiner.on(",").skipNulls();
301 try {
302 j.withKeyValueSeparator("/");
303 fail();
304 } catch (UnsupportedOperationException expected) {
305 }
306 }
307
308 private static class DontStringMeBro implements CharSequence {
309 @Override
310 public int length() {
311 return 3;
312 }
313 @Override
314 public char charAt(int index) {
315 return "foo".charAt(index);
316 }
317 @Override
318 public CharSequence subSequence(int start, int end) {
319 return "foo".subSequence(start, end);
320 }
321 @Override public String toString() {
322 throw new AssertionFailedError("shouldn't be invoked");
323 }
324 }
325
326
327 private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> {
328 private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4);
329 private final Iterator<Integer> iterator;
330 public IterableIterator() {
331 this.iterator = iterator();
332 }
333 @Override public Iterator<Integer> iterator() {
334 return INTEGERS.iterator();
335 }
336 @Override public boolean hasNext() {
337 return iterator.hasNext();
338 }
339 @Override public Integer next() {
340 return iterator.next();
341 }
342 @Override public void remove() {
343 iterator.remove();
344 }
345 }
346 }
347